home *** CD-ROM | disk | FTP | other *** search
/ Ian & Stuart's Australian Mac: Not for Sale / Another.not.for.sale (Australia).iso / fade into you / being there / Issues & Ideas / Anonymous remailers / Remailers / chain Folder / chain.c next >
Text File  |  1993-06-04  |  9KB  |  369 lines

  1. /*
  2.  *  chain.c
  3.  *    Chain Cypherpunks remailers for effective encryption
  4.  *    Usage: chain [-r] address remailer [...]
  5.  *    -r means to create an anonymous return address and print it.
  6.  *    No -r means to set up the standard input for sending.
  7.  *    This file is intended to be viewed with tab stop spacing of 4 chars.
  8.  *    This program is released into the public domain.
  9.  *    Version 1.0, May 31, 1993 - Hal Finney
  10.  *        Tested on MSDOS and Sun Unix systems.
  11.  */
  12.  
  13. #include <stdio.h>
  14. #include <ctype.h>
  15.  
  16. #ifdef MSDOS
  17. #define PATH_SEP "\\"
  18. #define XPATH 128
  19. #else
  20. #define PATH_SEP "/"
  21. #define XPATH 256
  22. #define SENDMAIL "/usr/lib/sendmail %s"
  23. #endif
  24.  
  25. #define REMFILE "chain.ini"
  26. #define PGPFLAGCHAR '*'
  27. #define PGPSTARTCHAR '-'
  28.  
  29. /* Global variables */
  30. char *pname;                /* Program name */
  31. int return_flag = 0;        /* 1 to create return address, else 0 */
  32. int encrypt_flag = 0;        /* 1 to encrypt for destination, else 0 */
  33. int sendmail_flag = 0;        /* 1 to pipe into sendmail.  Only for Unix */
  34. char *subject = NULL;        /* Subject to use on final step in chain */
  35. FILE *frem;                    /* Remailer list file */
  36. char buff[2*XPATH + 40];    /* Temp buffer */
  37.  
  38. /* Forward definitions */
  39. FILE *openremfile();
  40. void swap_cpp ();
  41. void userr();
  42. void filecopy ();
  43. void do_pgp ();
  44. void add_header ();
  45.  
  46. main (argc, argv)
  47. int    argc;
  48. char    **argv;
  49. {
  50.     int pgpflag, prevpgpflag;
  51.     FILE *f;
  52.     FILE *fout = stdout;
  53.     int i;
  54.     char dest[XPATH], remailer_address[XPATH];
  55.     char infilenm[XPATH], outfilenm[XPATH];
  56.     char *infile=infilenm, *outfile=outfilenm;
  57.     extern char *mktemp();
  58.     extern char *getenv();
  59.     extern FILE *popen();
  60.  
  61.     /* Parse command-line arguments */
  62.     pname = argv[0];  ++argv;  --argc;
  63.     while (argv[0]  &&  argv[0][0] == '-') {
  64.         char c, *opt = argv[0];
  65.         while (c = *++opt) {
  66.             switch (c) {
  67.             case 'r':    return_flag = 1; break;
  68. #ifdef SENDMAIL
  69.             case 'm':    sendmail_flag = 1; break;
  70. #endif
  71.             case 's':    if (opt[1] || !argv[1])
  72.                             userr();
  73.                         ++argv; --argc;
  74.                         subject = argv[0];
  75.                         break;
  76.             case 'e':    encrypt_flag = 1; break;
  77.             default:    fprintf (stderr, "Unrecognized option: %c\n", c);
  78.                         userr();
  79.                         break;
  80.             }
  81.         }
  82.         ++argv; --argc;
  83.     }
  84.  
  85.     if (argc < 2)
  86.         userr();
  87.     
  88.     if ((subject || encrypt_flag || sendmail_flag) && return_flag)
  89.         userr();
  90.  
  91.     /* Remember destination address */
  92.     strcpy (dest, argv[0]);  ++argv;  --argc;
  93.  
  94.     /* Open remailer file */
  95.     frem = openremfile();
  96.  
  97.     /* Name temp files */
  98.     infile[0] = outfile[0] = '\0';
  99.     if (getenv("TMP")) {
  100.         strcpy (infile, getenv("TMP"));
  101.         strcpy (outfile, infile);
  102.         strcat (infile, PATH_SEP);
  103.         strcat (outfile, PATH_SEP);
  104.     }
  105.     strcat (infile, mktemp ("c1XXXXXX"));
  106.     strcat (outfile, mktemp ("c2XXXXXX"));
  107.  
  108.     if (!(f = fopen(infile, "w"))) {
  109.         fprintf (stderr, "Unable to open temp file %s for output\n", infile);
  110.         exit (2);
  111.     }
  112.     if (!return_flag) {
  113.         /* Copy standard input to temp file */
  114.         filecopy (stdin, f);
  115.     }
  116.     fclose (f);
  117.  
  118.     /* If encrypting for destination, do that now. */
  119.     if (encrypt_flag) {
  120.         do_pgp (infile, outfile, dest);
  121.         swap_cpp (&infile, &outfile);
  122.     }
  123.  
  124.     /* Loop for all remailers */
  125.     prevpgpflag = 0;
  126.     for (i=argc-1; i>=0; i--) {
  127.         if (!find_remailer (argv[i], &pgpflag, remailer_address)) {
  128.             fprintf (stderr, "Unable to find remailer matching '%s'\n", argv[i]);
  129.             unlink (infile); unlink (outfile);
  130.             exit (5);
  131.         }
  132.         add_header (infile, outfile, 1, prevpgpflag, dest, subject);
  133.         subject = NULL;            /* Only use it once */
  134.         swap_cpp (&infile, &outfile);
  135.         if (pgpflag) {
  136.             do_pgp (infile, outfile, remailer_address);
  137.             swap_cpp (&infile, &outfile);
  138.             if (i==0) {
  139.                 /* Add "Encrypted: PGP" on last pass */
  140.                 add_header (infile, outfile, 0, 1, NULL);
  141.                 swap_cpp (&infile, &outfile);
  142.             }
  143.         }
  144.         prevpgpflag = pgpflag;
  145.         strcpy (dest, remailer_address);
  146.     }
  147.     if (!(f = fopen(infile, "r"))) {
  148.         fprintf (stderr, "Unable to open temp file %s for input\n", infile);
  149.         unlink (infile); unlink (outfile);
  150.         exit (2);
  151.     }
  152.  
  153. #ifdef SENDMAIL
  154.     if (sendmail_flag) {
  155.         /* Open pipe to SENDMAIL */
  156.         sprintf (buff, SENDMAIL, remailer_address);
  157.         if (!(fout = popen(buff, "w"))) {
  158.             fprintf (stderr, "Unable to open sendmail pipe: %s\n", buff);
  159.             exit (2);
  160.         }
  161.         fprintf (fout, "To: %s\n", dest);
  162.         fprintf (fout, "From: Chain program\n");
  163.         fprintf (fout, "\n");
  164.     }
  165. #endif /* SENDMAIL */
  166.  
  167.     if (return_flag) {
  168.         fprintf (fout, "Copy the material between the \"cut here\" lines below and put it\n");
  169.         fprintf (fout, "at the top of your reply message, then send the message to:\n");
  170.         fprintf (fout, "%s\n", remailer_address);
  171.         fprintf (fout, "\n");
  172.         fprintf (fout, "vvvvvvvvvvvvvvvvvvvvvvv cut here vvvvvvvvvvvvvvvvvvvvvvv\n");
  173.     }
  174.     filecopy (f, fout);
  175.     fclose (f);
  176.     if (return_flag)
  177.         fprintf (fout, "^^^^^^^^^^^^^^^^^^^^^^^ cut here ^^^^^^^^^^^^^^^^^^^^^^^\n");
  178. #ifdef SENDMAIL
  179.     if (sendmail_flag)
  180.         pclose (fout);
  181. #endif /* SENDMAIL */
  182.     unlink (infile);  unlink (outfile);
  183. }
  184.  
  185. /* Add up to two headers to the infile.  If request_flag is true, add
  186.  * "::\nRequest-Remailing-To: <dest>\n\n".  If enc_flag is true, then add
  187.  * "::\nEncrypted: PGP\n\n".  Then copy the rest of the file unless infile
  188.  * is null.
  189.  * If subject is non-NULL then add a Subject line after the
  190.  * Request-Remailing-To line.
  191.  */
  192. void
  193. add_header (infile, outfile, request_flag, enc_flag, dest, subject)
  194. char *infile, *outfile;
  195. int request_flag, enc_flag;
  196. char *dest;
  197. char *subject;
  198. {
  199.     FILE *f1, *f2;
  200.  
  201.     if (infile && !(f1 = fopen (infile, "r"))) {
  202.         fprintf (stderr, "Unable to open temp file %s for input\n", infile);
  203.         unlink (infile); unlink (outfile);
  204.         exit (3);
  205.     }
  206.     if (!(f2 = fopen (outfile, "w"))) {
  207.         fprintf (stderr, "Unable to open temp file %s for output\n", outfile);
  208.         if (infile) {
  209.             fclose (f1);
  210.             unlink (infile);
  211.         }    
  212.         unlink (outfile);
  213.         exit (3);
  214.     }
  215.     if (request_flag) {
  216.         fprintf (f2, "::\nRequest-Remailing-To: %s\n", dest);
  217.         if (subject)
  218.             fprintf (f2, "Subject: %s\n", subject);
  219.         fprintf (f2, "\n");
  220.     }
  221.     if (enc_flag)
  222.         fprintf (f2, "::\nEncrypted: PGP\n\n");
  223.     
  224.     if (infile) {
  225.         filecopy (f1, f2);
  226.         fclose (f1);
  227.         unlink (infile);
  228.     }
  229.     fclose (f2);
  230. }
  231.  
  232. /* Do PGP encryption to the infile, putting the result into the outfile.
  233.  * rem_address will be used to look up the PGP key to use.
  234.  */
  235. void
  236. do_pgp (infile, outfile, rem_address)
  237. char *infile, *outfile;
  238. char *rem_address;
  239. {
  240.     FILE *f = NULL;
  241.     int stat;
  242.  
  243.     sprintf (buff, "pgp -feat %s < %s > %s", rem_address, infile, outfile);
  244.     stat = system(buff);
  245.     /* Must check for error rather carefully - output file must start with
  246.      * '-'.  "system" does not really return a valid status code for us.
  247.      */
  248.     if (stat != 0 ||
  249.             !(f = fopen(outfile, "r")) || fread(buff, 1, 1, f) != 1  ||
  250.             buff[0] != PGPSTARTCHAR) {
  251.         fprintf (stderr, "PGP abnormal exit, status %d\n", stat);
  252.         if (f)
  253.             fclose (f);
  254.         unlink (infile); unlink (outfile);
  255.         exit (4);
  256.     }
  257.     fclose (f);
  258.     unlink (infile);
  259. }
  260.  
  261. void
  262. filecopy (f1, f2)
  263. FILE *f1, *f2;
  264. {
  265.     int c;
  266.  
  267.     while ((c = getc(f1)) != EOF)
  268.         putc (c, f2);
  269. }
  270.  
  271. /* Print out a usage error message and exit */
  272. void
  273. userr()
  274. {
  275. #ifdef SENDMAIL
  276.     fprintf (stderr, "Usage: %s [-rme] [-s subject] dest remailer [...]\n", pname);
  277. #else
  278.     fprintf (stderr, "Usage: %s [-re] [-s subject] dest remailer [...]\n", pname);
  279. #endif
  280.     fprintf (stderr, "-r means to print an anonymous return address\n");
  281.     fprintf (stderr, "else create message to chain stdin through remailers\n");
  282. #ifdef SENDMAIL
  283.     fprintf (stderr, "-m means to pipe output into sendmail and mail it\n");
  284. #endif
  285.     fprintf (stderr, "-e means to encrypt for the destination\n");
  286.     fprintf (stderr, "-s sets the specified subject for the outgoing message\n");
  287.     exit (1);
  288. }
  289.  
  290. /* Open the remailer init file.  First try the local directory, and if it
  291.  * is not there and PGPPATH is defined try that directory.
  292.  * Exit with an error if can't find it, else return an open file descriptor.
  293.  */
  294. FILE *
  295. openremfile()
  296. {
  297.     FILE *f;
  298.     char *pp;
  299.     char remfile[XPATH];
  300.     extern char *getenv();
  301.  
  302.     pp = getenv("PGPPATH");
  303.     if (f = fopen(REMFILE, "r"))
  304.         return f;
  305.     if (pp) {
  306.         strcpy (remfile, pp);
  307.         strcat (remfile, PATH_SEP);
  308.         strcat (remfile, REMFILE);
  309.         if (f = fopen(remfile, "r"))
  310.             return f;
  311.     }
  312.     fprintf (stderr, "Unable to read remailer list file %s\n", REMFILE);
  313.     exit (2);
  314. }
  315.  
  316. /* Look up remailer based on substring and fill in full_name, pgp flag */
  317. /* File format is a list of remailers, one per line, with a * as the first
  318.  * char if it has PGP.  Return 1 if find it, 0 if no matches.
  319.  */
  320. int
  321. find_remailer (str, ppflag, full_name)
  322. char *str;            /* Substring of name */
  323. int *ppflag;        /* Pointer to flag for whether it has PGP */
  324. char *full_name;    /* Full name */
  325. {
  326.     char buf[XPATH];
  327.     char *p, *p1;
  328.     char c;
  329.     int len;
  330.  
  331.     fseek (frem, 0L, 0);
  332.     c = *str; len = strlen(str);
  333.     while (fgets (buf, sizeof(buf), frem)) {
  334.         for (p=buf; *p; ++p) {
  335.             if (*p == c) {
  336.                 if (strncmp (p, str, len) == 0) {
  337.                     /* Found it */
  338.                     p = buf;
  339.                     if (*p == PGPFLAGCHAR) {
  340.                         *ppflag = 1;
  341.                         ++p;
  342.                     } else
  343.                         *ppflag = 0;
  344.                     /* Skip past blanks, then null-terminate at next blank */
  345.                     while (*p && isspace(*p))
  346.                         ++p;
  347.                     p1 = p;
  348.                     while (*p && !isspace(*p) && (*p!='\n'))
  349.                         ++p;
  350.                     *p = '\0';
  351.                     strcpy (full_name, p1);
  352.                     return 1;
  353.                 }
  354.             }
  355.         }
  356.     }
  357.     return 0;
  358. }
  359.                     
  360.  
  361. /* Swap two pointers */
  362. void
  363. swap_cpp (p1, p2)
  364. char **p1, **p2;
  365. {
  366.     char *t;
  367.     t = *p1; *p1 = *p2; *p2 = t;
  368. }
  369.